package com.ice.work.moment.crawler.processor;

import cn.hutool.core.util.ReflectUtil;
import cn.hutool.core.util.StrUtil;
import com.google.common.collect.Maps;
import com.honeybee.cloud.framework.common.constant.CommonSystemConstant;
import com.honeybee.cloud.framework.common.enums.DataStatusEnum;
import com.honeybee.cloud.framework.common.idwork.IdWorker;
import com.ice.work.moment.crawler.service.IFundPositionService;
import com.ice.work.moment.crawler.service.IInstitutionalPositionService;
import com.ice.work.moment.crawler.service.IShareService;
import com.ice.work.moment.crawler.service.IlPositionTypeService;
import com.ice.work.moment.facade.crawler.analytical.FundPositionAnalyticalObject;
import com.ice.work.moment.facade.crawler.analytical.InstitutionalPositionAnalyticalObject;
import com.ice.work.moment.facade.crawler.dto.PositionTypeDTO;
import com.ice.work.moment.facade.crawler.dto.ShareDTO;
import com.ice.work.moment.facade.crawler.enums.FundPositionEnum;
import com.ice.work.moment.facade.crawler.enums.InstitutionalPositionEnum;
import com.ice.work.moment.facade.crawler.mapper.AnalyticalObjectConvertMapper;
import com.ice.work.moment.facade.crawler.model.FundPosition;
import com.ice.work.moment.facade.crawler.model.InstitutionalPosition;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import us.codecraft.webmagic.Page;
import us.codecraft.webmagic.processor.PageProcessor;
import us.codecraft.webmagic.selector.Html;
import us.codecraft.webmagic.selector.Selectable;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @Description 机构持仓类型
 * @Author DELL
 * @Create 2019-04-29
 * @Since 1.0.0
 */
@Slf4j
@Component
@SuppressWarnings("all")
public class PositionProcessor extends BaseProcessor implements PageProcessor {

    @Autowired
    private IdWorker idWorker;
    @Autowired
    private IShareService shareService;
    @Autowired
    private IInstitutionalPositionService institutionalPositionService;
    @Autowired
    private IlPositionTypeService typeService;

    @Autowired
    private IFundPositionService fundPositionService;

    @Override
    public void process(Page page) {
        try {
            Html html = page.getHtml();
            log.info("机构持仓原文:{}", html.get());
            List<Selectable> trSelectableList = html.xpath("//*[@id='content']/table[2]/tbody/tr").nodes();
            if (CollectionUtils.isEmpty(trSelectableList) || CollectionUtils.size(trSelectableList) == 1) {
                log.info("无法获得机构持仓原文");
                return;
            }
            String url = page.getUrl().get();
            String type = url.substring(url.indexOf("ndk=") + 4, url.indexOf("&xztj="));
            PositionTypeDTO typeDTO = typeService.findByValue(type);
            if (Objects.isNull(typeDTO)) {
                log.error("无法获取到机构持仓类型:{}", type);
                return;
            }

            int i = 1;
            do {
                Selectable trSelectable = trSelectableList.get(i);
                log.info("爬取机构持仓内容:{}", trSelectable.get());
                i++;
                //处理机构持仓内容
                InstitutionalPositionAnalyticalObject analyticalObject = new InstitutionalPositionAnalyticalObject();
                ShareDTO shareDTO = null;
                Object obj = getValues(analyticalObject, trSelectable, false);
                analyticalObject = (InstitutionalPositionAnalyticalObject) obj;
                if (Objects.isNull(analyticalObject)) {
                    log.info("无法获取到机构持仓解析数据");
                    continue;
                }
                if (Objects.nonNull(analyticalObject.getShareCode()) && !analyticalObject.getShareCode().contains(CommonSystemConstant.HYPHEN)) {
                    log.info("机构持仓内容处理结果:{}", analyticalObject);
                    shareDTO = shareService.findByShareCode(analyticalObject.getShareCode());
                    if (Objects.isNull(shareDTO)) {
                        log.error("无法获取到股票代码:{}", analyticalObject.getShareCode());
                        continue;
                    }
                    InstitutionalPosition institutionalPosition = AnalyticalObjectConvertMapper.INSTANCE.toModel(analyticalObject);
                    institutionalPosition.setId(idWorker.nextId());
                    institutionalPosition.setShareId(shareDTO.getId());
                    institutionalPosition.setPositionTypeId(typeDTO.getId());
                    institutionalPosition.setDataStatus(DataStatusEnum.VALID.key);
                    institutionalPosition.setCreateAt(new Date());
                    institutionalPositionService.saveOrUpdate(institutionalPosition);
                    continue;
                }

                //处理基金重仓内容
                FundPositionAnalyticalObject fundPositionAnalyticalObject = new FundPositionAnalyticalObject();
                fundPositionAnalyticalObject = (FundPositionAnalyticalObject) getValues(fundPositionAnalyticalObject, trSelectable, true);
                log.info("基金重仓内容处理结果:{}", fundPositionAnalyticalObject);
                if (Objects.isNull(fundPositionAnalyticalObject)) {
                    log.info("无法获取到基金重仓内容解析数据");
                    continue;
                }
                shareDTO = shareService.findByShareCode(fundPositionAnalyticalObject.getShareCode());
                if (Objects.isNull(shareDTO)) {
                    log.error("无法获取到股票代码:{}", fundPositionAnalyticalObject.getShareCode());
                    continue;
                }
                FundPosition fundPosition = AnalyticalObjectConvertMapper.INSTANCE.toModel(fundPositionAnalyticalObject);
                fundPosition.setId(idWorker.nextId());
                fundPosition.setShareId(shareDTO.getId());
                fundPosition.setPositionTypeId(typeDTO.getId());
                fundPosition.setDataStatus(DataStatusEnum.VALID.key);
                fundPosition.setCreateAt(new Date());
                fundPositionService.saveOrUpdate(fundPosition);

            } while (i < trSelectableList.size());
        } catch (Exception e) {
            log.error("爬取机构持仓异常", e);
        }

    }


    /**
     * 获取列值
     *
     * @param trSelectable
     * @return
     */
    private Object getValues(Object obj, Selectable trSelectable, boolean isFund) {
        Class clazz = obj.getClass();
        Field[] fields = ReflectUtil.getFields(clazz);
        Method[] methods = ReflectUtil.getMethods(clazz);
        Map<String, Field> fieldMap = Arrays.stream(fields).collect(Collectors.toMap(Field::getName, a -> a, (k1, k2) -> k1));
        Map<String, Method> methodMap = Arrays.stream(methods).collect(Collectors.toMap(Method::getName, a -> a, (k1, k2) -> k1));
        List<Selectable> tdSelectableList = trSelectable.xpath("//td").nodes();
        Map<Integer, String> resultMap = Maps.newConcurrentMap();
        for (int j = 0; j < tdSelectableList.size(); j++) {
            try {
                Selectable tdSelectable = tdSelectableList.get(j);
                //获取内容
                String value = null;
                List<Selectable> aSelectableList = tdSelectable.xpath("//a").nodes();
                if (CollectionUtils.isNotEmpty(aSelectableList)) {
                    value = tdSelectable.xpath("//a/text()").get();
                }
                if (StringUtils.isEmpty(value)) {
                    List<Selectable> nobrSelectableList = tdSelectable.xpath("//nobr").nodes();
                    if (CollectionUtils.isNotEmpty(nobrSelectableList)) {
                        value = tdSelectable.xpath("//nobr/text()").get();
                    }
                }
                if (StringUtils.isEmpty(value)) {
                    List<Selectable> fontSelectableList = tdSelectable.xpath("//font").nodes();
                    if (CollectionUtils.isNotEmpty(fontSelectableList)) {
                        value = tdSelectable.xpath("//font/text()").get();
                    }
                }
                if (StringUtils.isEmpty(value)) {
                    value = trSelectable.xpath("//td/text()").nodes().get(j).get();
                }
                resultMap.put(j, StrUtil.trim(value));
            } catch (Exception e) {
                log.error("爬取机构持仓处理异常", e);
            }
        }
        log.info("机构持仓全部处理结果:{}", resultMap);
        resultMap.forEach((key, value) ->
        {
            try {
                String code = null;
                if (!isFund) {
                    code = InstitutionalPositionEnum.getCodeByKey(key);
                } else {
                    code = FundPositionEnum.getCodeByKey(key);
                }
                if (Objects.nonNull(code)) {
                    Field field = fieldMap.get(code);
                    if (Objects.nonNull(field)) {
                        Method method = methodMap.get(StrUtil.genSetter(field.getName()));
                        if (Objects.nonNull(method)) {
                            method.invoke(obj, StrUtil.trim(value));
                        }
                    }
                }
            } catch (Exception e) {
                log.error("机构持仓处理异常", e);
            }
        });
        return obj;
    }

}
